package stock

import (
	"fmt"
	"strings"

	"gitee.com/lyuanbo/stock-plus/internal/svc"
	"gitee.com/lyuanbo/stock-plus/pkg/consts"
	"gitee.com/lyuanbo/stock-plus/pkg/message"
	storagememory "gitee.com/lyuanbo/stock-plus/pkg/stock/storage_memory"
	"gitee.com/lyuanbo/stock-plus/pkg/stock/types"
	"gitee.com/lyuanbo/stock-plus/pkg/worker_manager"
	"github.com/bytedance/sonic"
	"github.com/nats-io/nats.go/jetstream"
	"github.com/shopspring/decimal"
	"go.uber.org/zap"
)

var _ workermanager.Tasker = (*StorageMemery)(nil)

func init() {
	workermanager.Register(func(svcCtx *svc.ServiceContext, cache *storagememory.Cache) workermanager.Tasker {
		return NewStorageMemery(svcCtx, cache)
	})
}

type StorageMemery struct {
	svcCtx   *svc.ServiceContext
	customer jetstream.Consumer
	cache    *storagememory.Cache
}

func NewStorageMemery(svcCtx *svc.ServiceContext, cache *storagememory.Cache) *StorageMemery {
	return &StorageMemery{svcCtx: svcCtx, customer: createCustomer(svcCtx.Ctx, "storage-memery-worker", svcCtx.JetStream, "default", consts.TopicRealTime), cache: cache}
}

func (s *StorageMemery) Name() string {
	return "storage.memery"
}

func (s *StorageMemery) Init() {
}

func (s *StorageMemery) Start() {
	go s.Run()
}

func (s *StorageMemery) Run() {
	_, _ = s.customer.Consume(func(msg jetstream.Msg) {
		var kline types.Kline
		err := sonic.Unmarshal(msg.Data(), &kline)
		if err != nil {
			s.svcCtx.Logger.Warn(s.svcCtx.Ctx, "storage.memery unmarshal kline error", zap.Error(err))
			_ = msg.Ack()
			return
		}

		// 过滤掉未持仓的股票
		if !kline.StockInfo.IsHeld {
			_ = msg.Ack()
			return
		}

		key := s.cache.GetKey(kline.StockInfo.Symbol, "realtime")
		rb := s.cache.GetRingBuffer(key)

		// 获取60
		rb.Mux.Lock()
		arr := rb.GetLast(-60)
		if len(arr) == 0 {
			rb.Mux.Unlock()
			rb.PushBack(&kline)
			_ = msg.Ack()
			return
		}

		maxClose := arr[0].KlineInfo.Close
		minClose := arr[0].KlineInfo.Close

		for _, kline := range arr[1:] {
			if kline.KlineInfo.Close.GreaterThan(maxClose) {
				maxClose = kline.KlineInfo.Close
			}
			if kline.KlineInfo.Close.LessThan(minClose) {
				minClose = kline.KlineInfo.Close
			}
		}

		// 计算涨跌幅（相对最高/最低价）
		dropFromMax := kline.KlineInfo.Close.Sub(maxClose).Div(maxClose).Mul(decimal.NewFromFloat(100)).Round(2)
		riseFromMin := kline.KlineInfo.Close.Sub(minClose).Div(minClose).Mul(decimal.NewFromFloat(100)).Round(2)

		dropRate, _ := dropFromMax.Float64() // 负数，如 -5.2%
		riseRate, _ := riseFromMin.Float64() // 正数，如 +3.8%

		brk := message.Message{Title: fmt.Sprintf("涨速提醒：%s", kline.StockInfo.Name), Level: message.LevelCritical, Url: fmt.Sprintf("https://xueqiu.com/S/%s", strings.ToUpper(kline.StockInfo.Symbol))}

		// 上涨检查：相对最低价涨幅超过阈值
		if riseRate >= s.svcCtx.Conf.Get().Realtime.UpVelocity {
			brk.Subtitle = fmt.Sprintf("1分钟上涨%s%%, 当前：%s, 最低：%s", riseFromMin.String(), kline.KlineInfo.Close.String(), minClose.String())
		}

		// 下跌检查：相对最高价跌幅超过阈值（用绝对值比较）
		if dropRate < 0 && dropRate <= s.svcCtx.Conf.Get().Realtime.DownVelocity {
			brk.Subtitle = fmt.Sprintf("1分钟下跌%s%%, 当前：%s, 最高：%s", dropFromMax.String(), kline.KlineInfo.Close.String(), maxClose.String())
		}

		rb.PushBack(&kline)
		rb.Mux.Unlock()

		if brk.Subtitle != "" {
			_ = s.svcCtx.Nats.Publish(consts.TopicMessage, brk.Marshal())
		}

		_ = msg.Ack()
	})
}
